package org.hcyspartnoc.demo.service.system.impl;

import cn.hutool.core.bean.BeanUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.github.yulichang.wrapper.MPJLambdaWrapper;
import org.apache.commons.codec.digest.DigestUtils;
import org.hcyspartnoc.demo.common.core.PageBean;
import org.hcyspartnoc.demo.common.core.configuration.UserConfiguration;
import org.hcyspartnoc.demo.common.core.configuration.UtilsConfiguration;
import org.hcyspartnoc.demo.common.core.context.BaseContextHolder;
import org.hcyspartnoc.demo.common.core.enums.CoreSysRole;
import org.hcyspartnoc.demo.common.enums.system.SysUserStatusEnum;
import org.hcyspartnoc.demo.common.exception.common.CommonUtilsException;
import org.hcyspartnoc.demo.common.exception.framework.AuthException;
import org.hcyspartnoc.demo.common.exception.system.SysRoleException;
import org.hcyspartnoc.demo.common.exception.system.SysUserException;
import org.hcyspartnoc.demo.mapper.system.SysRoleMapper;
import org.hcyspartnoc.demo.mapper.system.SysRoleUserMapper;
import org.hcyspartnoc.demo.mapper.system.SysUserMapper;
import org.hcyspartnoc.demo.pojo.dto.system.*;
import org.hcyspartnoc.demo.pojo.po.system.SysRolePo;
import org.hcyspartnoc.demo.pojo.po.system.SysRoleUserPo;
import org.hcyspartnoc.demo.pojo.po.system.SysUserPo;
import org.hcyspartnoc.demo.pojo.vo.system.SysRolesVo;
import org.hcyspartnoc.demo.pojo.vo.system.SysUserVo;
import org.hcyspartnoc.demo.service.system.ISysUserService;
import org.hcyspartnoc.demo.utils.AliyunOssUtils;
import org.hcyspartnoc.demo.utils.StringUtils;
import org.hcyspartnoc.demo.utils.WeiXinUtils;
import org.hcyspartnoc.demo.utils.redis.RedisComponent;
import org.springframework.beans.BeanUtils;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.multipart.MultipartFile;

import javax.annotation.Resource;
import java.io.IOException;
import java.time.LocalDateTime;
import java.util.*;

@Service
public class SysUserServiceImpl extends ServiceImpl<SysUserMapper, SysUserPo> implements ISysUserService {
    @Resource
    private SysUserMapper sysUserMapper;
    @Resource
    private UserConfiguration userConfiguration;
    @Resource
    private RedisComponent redisComponent;
    @Resource
    private AliyunOssUtils aliyunOssUtils;
    @Resource
    private SysRoleMapper sysRoleMapper;
    @Resource
    private SysRoleUserMapper sysRoleUserMapper;
    @Resource
    private UtilsConfiguration utilsConfiguration;


//    @Override
//    @Transactional
//    public String registerByPhone(SysUserPhoneRegisterDto sysUserPhoneRegisterDto) throws SysUserException{
//        // 1. 检查手机号是否已经注册
//        String phoneNumber = sysUserPhoneRegisterDto.getPhone();
//        SysUser existingUser = sysUserMapper.selectUserByPhoneNumber(phoneNumber);
//        if (existingUser != null) {
//            throw new SysUserException(SysUserException.PHONE_HAS_EXISTS);
//        }
//        // 2. 创建新用户
//        SysUser newUser = new SysUser();
//        newUser.setPhoneNumber(phoneNumber);
//        newUser.setUsername(sysUserPhoneRegisterDto.getUsername());
//        newUser.setPassword(passwordEncoder.encode(sysUserPhoneRegisterDto.getPassword()));  // 加密密码
//        newUser.setCreateTime(LocalDateTime.now());
//        newUser.setStatus("ACTIVE"); // 根据你的业务逻辑设置用户状态
//        // 3. 保存新用户到数据库
//        int insertResult = sysUserMapper.insertUser(newUser);
//        if (insertResult != 1) {
//            throw new SysUserException("用户注册失败，请稍后再试");
//        }
//        // 4. 生成 JWT 或其他类型的 Token
//        String token = tokenService.generateToken(newUser);
//        // 5. 返回 Token
//        return token;
//    }

    @Override
    @Transactional
    public String registerByWx(SysUserWxRegisterDto sysUserWxRegisterDto) throws SysUserException {
        String sessionKeyOrOpenId = WeiXinUtils.getSessionKeyOrOpenId(sysUserWxRegisterDto.getJsCode());
        if (sessionKeyOrOpenId == null)// 抛出异常
            throw new SysUserException(SysUserException.JS_CODE_NOT_RIGHT);
        // 查询数据表是否存在当前用户，存在直接查询，不存在则创建用户
        SysUserPo savedUserPo = sysUserMapper.selectOne(new LambdaQueryWrapper<>(SysUserPo.class).eq(SysUserPo::getOpenId, sessionKeyOrOpenId));
        Integer uid;
        if (savedUserPo == null) {
            // 注册用户
            SysUserPo sysUserPo = new SysUserPo();
            Collections.shuffle(userConfiguration.getDefaultAvatar());
            sysUserPo.setAvatar(userConfiguration.getDefaultAvatar().get(0));
            sysUserPo.setOpenId(sessionKeyOrOpenId);
            sysUserPo.setNickname("用户_" + StringUtils.randomStr(10));
            String md5Pwd = StringUtils.encodeByMd5(StringUtils.randomStr(16), userConfiguration.getPwdSalt());
            sysUserPo.setPassword(md5Pwd);
            // 插入用户
            sysUserMapper.insert(sysUserPo);
            uid = sysUserPo.getId();
            // 将用户角色绑定为普通用户
            SysRoleUserPo sysRoleUserPo = new SysRoleUserPo();
            sysRoleUserPo.setUserId(uid);
            sysRoleUserPo.setRoleId(CoreSysRole.NORMAL_USER.getId());
            sysRoleUserMapper.insert(sysRoleUserPo);
            // 将用户关系加载到redis
            redisComponent.setRU_Relation(uid, sysRoleUserPo.getRoleId());
        } else {
            if (savedUserPo.getStatus().equals(SysUserStatusEnum.DISABLE.getCode()))
                throw new SysUserException(SysUserException.USER_STATUS_ERROR);
            uid = savedUserPo.getId();
        }
        // 刷新最后登录时间
        reFleshLastLoginTime(uid);
        // 生成token将用户id和数据token建立关系
        return generateToken(uid);
    }

    @Override
    @Transactional
    public SysUserVo loginByAccount(SysUserLoginByPhoneDto sysUserLoginByPhoneDto) throws SysUserException, CommonUtilsException {
        // 获取用户
        SysUserPo sysUserPo = sysUserMapper.selectOne(new LambdaQueryWrapper<>(SysUserPo.class)
                .eq(SysUserPo::getAccount, sysUserLoginByPhoneDto.getAccount()));
        System.out.println(sysUserPo);
        // 用户不存在
        if (Objects.isNull(sysUserPo))
            throw new SysUserException(SysUserException.USER_NOT_EXISTS);
        // 用户状态异常
        if (sysUserPo.getStatus().equals(SysUserStatusEnum.DISABLE.getCode()))
            throw new SysUserException(SysUserException.USER_STATUS_ERROR);
        // 验证密码
        String encodePwd = StringUtils.encodeByMd5(sysUserLoginByPhoneDto.getPassword(), userConfiguration.getPwdSalt());
        if (!sysUserPo.getPassword().equals(encodePwd))
            throw new SysUserException(SysUserException.PASSWORD_NOT_RIGHT);
        // 刷新最后登录时间
        reFleshLastLoginTime(sysUserPo.getId());
        String token = generateToken(sysUserPo.getId());
        SysUserVo userVo = new SysUserVo();
        userVo.setId(sysUserPo.getId());
//        userVo.setAvatarUrl(sysUserPo.getAvatar());
        userVo.setNickname(sysUserPo.getNickname());
        userVo.setToken(token);
        // 生成token将用户id和数据token建立关系
        return userVo;
    }

    @Override
    @Transactional
    public void logout() throws SysUserException {
        SysUserPo currentUser = BaseContextHolder.getContext().getBaseCurrentUser();
        if (currentUser.getRoleId().equals(CoreSysRole.SUPER_ADMIN.getId()))
            throw new SysUserException(SysUserException.SUPER_ADMIN_COULD_NOT_LOGOUT);
        this.removeById(currentUser.getId());
    }

    @Override
    @Transactional
    public String modifyAvatar(MultipartFile image) throws CommonUtilsException, SysUserException {
        // 验证图像文件合法性 TODO
        String originalFilename = null;
        //获取原始的文件名
        if (Objects.isNull(originalFilename = image.getOriginalFilename()))
            throw new CommonUtilsException(CommonUtilsException.SRC_NOT_RIGHT);
        //在oss中存储名字就是UUID + 文件的后缀名
        String fileExtension = originalFilename.substring(originalFilename.lastIndexOf(".") + 1);
        if (!utilsConfiguration.getFile().getAllowedImageTypes().contains(fileExtension.toUpperCase()))
            throw new CommonUtilsException(CommonUtilsException.SRC_NOT_RIGHT);
        String objectName = UUID.randomUUID() + "." + fileExtension;
        try {
            String resultURL = aliyunOssUtils.upload(image.getBytes(), objectName);
            if (Objects.isNull(resultURL))
                throw new CommonUtilsException(CommonUtilsException.SRC_UPLOAD_FAIL);
            // 通过上下文获取当前用户
            SysUserPo currentUser = BaseContextHolder.getContext().getBaseCurrentUser();
            // 修改数据库 -> 将objectName设置为新的avtar
            sysUserMapper.update(new LambdaUpdateWrapper<>(SysUserPo.class)
                    .set(SysUserPo::getAvatar, objectName)
                    .eq(SysUserPo::getId, currentUser.getId()));
            currentUser.setAvatar(objectName);
            return resultURL;
        } catch (IOException e) {
            throw new CommonUtilsException(CommonUtilsException.SRC_UPLOAD_FAIL);
        }
    }

    @Override
    @Transactional
    public void modifyPassword(SysUserModifyPwdDto sysUserModifyPwdDto) throws SysUserException {
        // 通过上下文获取当前用户
        SysUserPo currentUser = BaseContextHolder.getContext().getBaseCurrentUser();
        SysUserPo sysUserPo = sysUserMapper.selectOne(new LambdaQueryWrapper<>(SysUserPo.class).eq(SysUserPo::getId, currentUser.getId()));
        // 验证当前用户旧密码是否正确
        String md5_oldPwd = StringUtils.encodeByMd5(sysUserModifyPwdDto.getOldPwd(), userConfiguration.getPwdSalt());
        if (!Objects.equals(md5_oldPwd, sysUserPo.getPassword()))
            throw new SysUserException(SysUserException.PASSWORD_NOT_RIGHT);
        // 修改密码为新密码
        String md5_newPwd = StringUtils.encodeByMd5(sysUserModifyPwdDto.getNewPwd(), userConfiguration.getPwdSalt());
        sysUserMapper.update(new LambdaUpdateWrapper<>(SysUserPo.class).set(SysUserPo::getPassword, md5_newPwd).eq(SysUserPo::getId, currentUser.getId()));
    }

    @Override
    @Transactional
    public void modifyBaseInfo(SysUserModifyBaseInfoDto sysUserModifyBaseInfoDto) {
        // 通过上下文获取当前用户
        SysUserPo currentUser = BaseContextHolder.getContext().getBaseCurrentUser();
        // 修改用户信息
        SysUserPo modifyUserPo = BeanUtil.copyProperties(sysUserModifyBaseInfoDto, SysUserPo.class);
        modifyUserPo.setId(currentUser.getId());
        saveOrUpdate(modifyUserPo);
    }

    @Override
    public SysUserVo queryByToken() {
        // 通过上下文获取当前用户
        return userPoToVo(BaseContextHolder.getContext().getBaseCurrentUser());
    }

    @Override
    @Transactional
    public void rebindingRole(SysUserRebindingRoleDto sysUserRebindingRoleDto) throws SysUserException, SysRoleException {
        // 如果修改后的角色为超级管理员则不允许修改
        if (sysUserRebindingRoleDto.getRoleId().equals(CoreSysRole.SUPER_ADMIN.getId()))
            throw new SysRoleException(SysRoleException.ROLE_COULD_NOT_ACT);
        // 检查当前用户是否存在
        SysUserPo sysUserPo = userNotExistsThrow(sysUserRebindingRoleDto.getUserId());
        // 如果被修改的用户的角色是超级管理员，则不允许修改
        if (sysUserPo.getRoleId().equals(CoreSysRole.SUPER_ADMIN.getId()))
            throw new SysRoleException(SysRoleException.ROLE_COULD_NOT_ACT);
        // 检查角色是否存在
        roleNotExistsThrow(sysUserRebindingRoleDto.getRoleId());
        // 替换角色
        sysRoleUserMapper.update(new LambdaUpdateWrapper<>(SysRoleUserPo.class).eq(SysRoleUserPo::getUserId, sysUserRebindingRoleDto.getUserId())
                .set(SysRoleUserPo::getRoleId, sysUserRebindingRoleDto.getRoleId()));
        // 修改redis关系
        redisComponent.setRU_Relation(sysUserRebindingRoleDto.getUserId(), sysUserRebindingRoleDto.getRoleId());
    }

    @Override
    @Transactional
    public void modifyStatus(SysUserModifyStatusDto sysUserModifyStatusDto) throws AuthException, SysUserException, SysRoleException {
        // 当前用户是超级管理员则不允许修改
        Integer ruRoleId = redisComponent.getRU_RoleId(sysUserModifyStatusDto.getUserId());
        if (Objects.isNull(ruRoleId))
            throw new SysUserException(SysUserException.USER_NOT_EXISTS);
        if (ruRoleId.equals(CoreSysRole.SUPER_ADMIN.getId()))
            throw new SysRoleException(SysRoleException.ROLE_COULD_NOT_ACT);
        SysUserStatusEnum newStatus = SysUserStatusEnum.getByCode(sysUserModifyStatusDto.getStatus());
        if (Objects.isNull(newStatus))
            throw new SysUserException(SysUserException.USER_STATUS_ERROR);
        int update = sysUserMapper.update(new LambdaUpdateWrapper<>(SysUserPo.class)
                .set(SysUserPo::getStatus, newStatus.getCode())
                .eq(SysUserPo::getId, sysUserModifyStatusDto.getUserId()));
        if (update == 0)
            throw new SysUserException(SysUserException.USER_NOT_EXISTS);
    }
    @Override
    @Transactional
    public PageBean<SysUserPo, SysUserVo> queryPage(Integer currentPage, Integer pageSize, String nickName, String account, List<Integer> roleIds, String sortField, String sortOrder) {
        QueryWrapper<SysUserPo> queryWrapper = new QueryWrapper<>();
        // 模糊查询昵称
        if (nickName != null && !nickName.isEmpty()) {
            queryWrapper.like("nickname", nickName);
        }
        // 模糊查询账号
        if (account != null && !account.isEmpty()) {
            queryWrapper.like("account", account);
        }
        // 角色 ID 筛选
        if (roleIds != null && !roleIds.isEmpty()) {
            queryWrapper.inSql("id", "SELECT user_id FROM sys_role_user WHERE role_id IN (" + String.join(",", roleIds.stream().map(String::valueOf).toArray(String[]::new)) + ")");
        }
        // 排序
        if (sortField != null && !sortField.isEmpty() && sortOrder != null && !sortOrder.isEmpty()) {
            if ("id".equals(sortField)) {
                if ("asc".equals(sortOrder)) {
                    queryWrapper.orderByAsc("id");
                } else if ("desc".equals(sortOrder)) {
                    queryWrapper.orderByDesc("id");
                }
            } else if ("account".equals(sortField)) {
                if ("asc".equals(sortOrder)) {
                    queryWrapper.orderByAsc("account");
                } else if ("desc".equals(sortOrder)) {
                    queryWrapper.orderByDesc("account");
                }
            } else if ("nickname".equals(sortField)) {
                if ("asc".equals(sortOrder)) {
                    queryWrapper.orderByAsc("nickname");
                } else if ("desc".equals(sortOrder)) {
                    queryWrapper.orderByDesc("nickname");
                }
            } else {
                queryWrapper.orderByAsc("id");
            }
        }
        Page<SysUserPo> page=new Page<>(currentPage,pageSize);
        Page<SysUserPo> page1 = sysUserMapper.selectPage(page, queryWrapper);
        List<SysUserPo> records = page1.getRecords();
        ArrayList<SysUserVo> sysUserVos = new ArrayList<>();
        for(SysUserPo sysUserPo:records){
            ArrayList<SysRolesVo> sysRolesVoArrayList=new ArrayList<>();
            SysUserVo sysUserVo=new SysUserVo();
            BeanUtils.copyProperties(sysUserPo,sysUserVo);
            Integer id = sysUserPo.getId();
            //查询角色id和角色名字
            List<Integer> roleids = sysRoleMapper.selectByidUser(id);
            for (Integer roleid:roleids){
                String  rolename=sysRoleMapper.selectByidRole(roleid);
                SysRolesVo sysRolesVo=new SysRolesVo();
                sysRolesVo.setId(roleid);
                sysRolesVo.setRoleName(rolename);
                sysRolesVoArrayList.add(sysRolesVo);
            }
            //把角色姓名封装到类里面
            sysUserVo.setRoles(sysRolesVoArrayList);
            List<String> list=sysRoleMapper.selectRoles();
            sysUserVo.setRoleNames(list);
            sysUserVos.add(sysUserVo);
        }
        return new PageBean<>(page1,sysUserVos);
    }
    @Override
    @Transactional
    public boolean saveOrUpdateUser(SysUserUpdateAndAddDto sysUserUpdateAndAddDto) {
        // 1. 新增或更新用户信息
        SysUserPo user = new SysUserPo();
        BeanUtils.copyProperties(sysUserUpdateAndAddDto, user);

        if (sysUserUpdateAndAddDto.getId() == null) {
            // 新增用户，密码必传
            if (sysUserUpdateAndAddDto.getPassword()!=null) {
                throw new IllegalArgumentException("新增用户时密码不能为空");
            }
            // 对密码进行加密（假设使用MD5加密）
            user.setPassword(DigestUtils.md5Hex(String.valueOf(sysUserUpdateAndAddDto.getPassword())));
            sysUserMapper.insert(user); // 保存用户
        } else {
            // 编辑用户，密码可选
            if (sysUserUpdateAndAddDto.getPassword()!=null) {
                user.setPassword(DigestUtils.md5Hex(String.valueOf(sysUserUpdateAndAddDto.getPassword())));
            }
            sysUserMapper.updateById(user); // 更新用户
        }
        //分配角色
        SysRoleUserPo sysRoleUserPo=new SysRoleUserPo();
        sysRoleUserPo.setUserId(user.getId());
        sysRoleUserPo.setRoleId(user.getRoleId());
        sysRoleUserMapper.insert(sysRoleUserPo);
        return true;
    }

    @Override
    @Transactional
    public void addNewUser(SysUserAddDto sysUserAddDto) {
        SysUserPo sysUserpo=new SysUserPo();
        BeanUtils.copyProperties(sysUserAddDto,sysUserpo);
        String password = sysUserpo.getPassword();
        String md5Pwd = StringUtils.encodeByMd5(StringUtils.randomStr(16), password);
        sysUserpo.setPassword(md5Pwd);
        sysUserpo.setCreateTime(LocalDateTime.now());
        sysUserpo.setLastLoginTime(LocalDateTime.now());
        sysUserpo.setStatus(1);
        sysUserpo.setAvatar("f83f73f7-3c3b-4517-a359-cb58c756c6ab.jpg");
        sysUserMapper.insert(sysUserpo);
        //寻找id
       Integer userid= sysUserMapper.selectUserByaccount(sysUserpo.getAccount());
        List<Integer> roleIds = sysUserAddDto.getRoleIds();
        for (Integer roleid:roleIds){
            sysUserMapper.addRoleid(roleid,userid);
        }
    }

    @Override
    public boolean updateUser(SysUserUpdateAndAddDto sysUserUpdateAndAddDto) {
        SysUserPo sysUserPo=new SysUserPo();
        BeanUtils.copyProperties(sysUserUpdateAndAddDto,sysUserPo);
        sysUserPo.setLastLoginTime(LocalDateTime.now());
        sysUserPo.setStatus(1);
        List<Integer> roleIds = sysUserUpdateAndAddDto.getRoleIds();
        Integer userid= sysUserMapper.selectUserByaccount(sysUserUpdateAndAddDto.getAccount());
        sysUserMapper.updateById(sysUserPo);
        int id=sysUserPo.getId();
        sysUserMapper.deleteallrole(sysUserPo.getId());
        for (Integer roleid:roleIds){
            sysUserMapper.addRoleid(roleid,userid);
        }
        return true;
    }

    @Override
    public void removeuserByid(Integer user) {


        sysUserMapper.removeuserByid(user);
        sysUserMapper.removeuserandrole(user);
    }

    private SysUserPo userNotExistsThrow(Integer uid) throws SysUserException {
        MPJLambdaWrapper<SysUserPo> wrapper = new MPJLambdaWrapper<SysUserPo>()
                .selectAll(SysUserPo.class)
                .selectAs(SysRoleUserPo::getRoleId, SysUserPo::getRoleId)
                .leftJoin(SysRoleUserPo.class, SysRoleUserPo::getUserId, SysUserPo::getId)
                .eq(SysUserPo::getId, uid);
        SysUserPo sysUserPo = getOne(wrapper);
        if (Objects.isNull(sysUserPo))
            throw new SysUserException(SysUserException.USER_NOT_EXISTS);
        return sysUserPo;
    }

    private SysRolePo roleNotExistsThrow(Integer roleId) throws SysRoleException {
        SysRolePo sysRolePo = sysRoleMapper.selectOne(new LambdaQueryWrapper<>(SysRolePo.class).eq(SysRolePo::getId, roleId));
        if (Objects.isNull(sysRolePo))
            throw new SysRoleException(SysRoleException.ROLE_NOT_EXISTS);
        return sysRolePo;
    }

    private SysUserVo userPoToVo(SysUserPo sysUserPo) {
        // 封装用户信息
        SysUserVo sysUserVo = BeanUtil.copyProperties(sysUserPo, SysUserVo.class);
        // 格式化时间
        sysUserVo.setFormatCreateTime(StringUtils.formatDateTime(sysUserPo.getCreateTime()));
        if (Objects.nonNull(sysUserPo.getLastLoginTime()))
            sysUserVo.setFormatLastLoginTime(StringUtils.formatDateTime(sysUserPo.getLastLoginTime()));
        // 获取头像地址
//        sysUserVo.setAvatarUrl(aliyunOssUtils.generateUrl(sysUserPo.getAvatar()));
        return sysUserVo;
    }

    private String generateToken(Integer uid) {
        // 生成token将用户id和数据token建立关系
        String partOne = StringUtils.encodeByMd5(uid.toString(), StringUtils.randomStr(32));
        String partTwo = StringUtils.randomStr(userConfiguration.getTokenLength());
        String token = partOne + partTwo;
        redisComponent.setToken(token, uid);
        return token;
    }

    private void reFleshLastLoginTime(Integer uid) {
        update(new LambdaUpdateWrapper<>(SysUserPo.class)
                .eq(SysUserPo::getId, uid)
                .set(SysUserPo::getLastLoginTime, LocalDateTime.now()));
    }

}
